<template>
  <div class="excalidraw-wrapper">
    <div class="share-button-container">
      <button
        v-if="isClient"
        class="share-button"
        @click="handleShare"
        title="分享画板"
      >
        <svg
          width="16"
          height="16"
          viewBox="0 0 24 24"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z"
            fill="currentColor"
          />
        </svg>
      </button>
    </div>
    <div
      v-if="isClient"
      ref="container"
      :style="{ height: '100%', border: '1px solid #eee' }"
    ></div>
    <div v-else>加载中...</div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, onUnmounted, nextTick, watch } from "vue";
import { Excalidraw } from "@excalidraw/excalidraw";
import React from "react";
import ReactDOM from "react-dom/client";
import "@excalidraw/excalidraw/index.css";
import { v4 as uuidv4 } from "uuid";
import { Client } from "@stomp/stompjs";
import { useStudyRoomStore, useUserStore, useExcalidrawStore } from "@/stores";
import { debounce, isEqual } from "lodash-es";
import { useRoute } from "vue-router";
import { ElMessage } from "element-plus";

const isClient = ref(false);
const container = ref(null);
let reactRoot = null;
const userStore = useUserStore();
const studyRoomStore = useStudyRoomStore();
const excalidrawStore = useExcalidrawStore();
const route = useRoute();
let MQClient = new Client();

let isReceivingUpdate = false;
let lastSentElements: any[] = [];
let lastReceivedTimestamp = 0;
let pendingLocalChanges = false;
let currentRoomId = "";
let localChangeBuffer: any[] = [];

const getRoomId = () => {
  let roomId;
  const routeParams = route.params;
  if (routeParams.token) {
    roomId = routeParams.token;
  } else if (studyRoomStore.currentRoom?.roomId) {
    roomId = studyRoomStore.currentRoom.roomId;
  } else if (excalidrawStore.currentRoomId) {
    roomId = excalidrawStore.currentRoomId;
  } else {
    roomId = uuidv4();
  }

  return roomId;
};

const initMQConnection = () => {
  currentRoomId = getRoomId();
  if (!currentRoomId) return;

  MQClient.configure({
    brokerURL: import.meta.env.VITE_MQ_WEBSOCKET_URL,
    connectHeaders: {
      login: import.meta.env.VITE_MQ_USERNAME,
      passcode: import.meta.env.VITE_MQ_PASSWORD,
      host: import.meta.env.VITE_MQ_HOST || "/",
    },
    debug: (str) => {
      if (!str.includes("PING") && !str.includes("PONG")) {
        console.debug("[STOMP]", str);
      }
    },
    reconnectDelay: 5000,
    heartbeatIncoming: 4000,
    heartbeatOutgoing: 4000,
    onConnect: () => {
      console.log("MQ连接成功 - Excalidraw协作");

      MQClient.subscribe(
        `/exchange/excalidraw_exchange/draw.${currentRoomId}`,
        (message) => {
          if (!message.body) return;

          try {
            const data = JSON.parse(message.body);

            if (data.sender === userStore.currentUser?.userId) return;

            console.log("收到远程更新", {
              sender: data.sender,
              elementCount: data.elements?.length,
            });

            const api = (window as any).excalidrawAPI;
            if (api && data.elements) {
              // 检查时间戳，避免应用过时的更新
              if (data.timestamp && data.timestamp < lastReceivedTimestamp) {
                console.log("忽略过时的远程更新");
                return;
              }

              lastReceivedTimestamp = data.timestamp || Date.now();

              // 标记正在接收远程更新，但不阻塞本地操作
              isReceivingUpdate = true;

              // 保存当前正在编辑的本地更改
              const currentElements = api.getSceneElements();
              const hasLocalChanges = !isEqual(
                currentElements,
                lastSentElements
              );

              if (hasLocalChanges && !pendingLocalChanges) {
                console.log("检测到本地未保存的更改，缓存中...");
                localChangeBuffer = JSON.parse(JSON.stringify(currentElements));
                pendingLocalChanges = true;
              }

              // 合并远程更新，但优先保留正在编辑的元素
              const mergedElements = mergeElements(
                data.elements,
                currentElements,
                data.sender
              );

              api.updateScene({
                elements: mergedElements,
                appState: {
                  ...api.getAppState(),
                  collaborators: [],
                },
                commitToHistory: false,
              });

              lastSentElements = mergedElements;
              excalidrawStore.setCurrentDrawing(currentRoomId, {
                elements: mergedElements,
                appState: {
                  ...api.getAppState(),
                  collaborators: [],
                },
              });

              // 短暂延迟后重置接收状态
              setTimeout(() => {
                isReceivingUpdate = false;
                // 如果有待处理的本地更改，重新发送
                if (pendingLocalChanges) {
                  const currentElements = api.getSceneElements();
                  if (!isEqual(currentElements, lastSentElements)) {
                    sendDrawingData(currentElements, api.getAppState());
                  }
                  pendingLocalChanges = false;
                  localChangeBuffer = [];
                }
              }, 50);
            }
          } catch (e) {
            console.error("消息解析失败:", e);
          }
        }
      );
    },
    onStompError: (frame) => {
      console.error("MQ连接错误:", frame.headers["message"]);
    },
    onDisconnect: () => {
      console.log("MQ连接断开");
    },
  });

  MQClient.activate();
};

// 元素合并函数，智能合并本地和远程更改
const mergeElements = (
  remoteElements: any[],
  localElements: any[],
  remoteSender: string
) => {
  const merged = [...remoteElements];
  const remoteIds = new Set(remoteElements.map((e) => e.id));

  // 保留本地新增的元素（ID不在远程元素中的）
  localElements.forEach((localElement) => {
    if (!remoteIds.has(localElement.id)) {
      // 检查是否是用户正在编辑的元素（最近修改的）
      const now = Date.now();
      if (!localElement.updated || now - localElement.updated < 5000) {
        merged.push({
          ...localElement,
          updated: now,
        });
      }
    }
  });

  return merged;
};

const sendDrawingData = debounce((elements: any[], appState: any) => {
  if (!MQClient.connected) return;

  // 即使在接收远程更新时也允许发送本地更改
  if (isReceivingUpdate) {
    pendingLocalChanges = true;
    return;
  }

  if (isEqual(elements, lastSentElements)) return;

  const timestamp = Date.now();
  lastSentElements = JSON.parse(JSON.stringify(elements));

  excalidrawStore.setCurrentDrawing(currentRoomId, {
    elements,
    appState: {
      ...appState,
      collaborators: [],
    },
  });

  MQClient.publish({
    destination: `/exchange/excalidraw_exchange/draw.${currentRoomId}`,
    body: JSON.stringify({
      elements,
      sender: userStore.currentUser?.userId,
      timestamp,
    }),
    headers: { "content-type": "application/json" },
  });
}, 150);

const handleShare = async () => {
  const api = (window as any).excalidrawAPI;
  if (!api) return;

  const elements = api.getSceneElements();
  const appState = api.getAppState();
  const roomId = getRoomId();
  if (!roomId) {
    ElMessage.error("无法获取房间ID，请稍后再试");
    return;
  }
  let shareUrl = "";
  //如果地址栏已经有id了
  if (route.params.token) {
    shareUrl = `${window.location.origin}${window.location.pathname}`;
  } else {
    shareUrl = `${window.location.origin}${window.location.pathname}/${roomId}`;
  }
  try {
    await navigator.clipboard.writeText(shareUrl);
    ElMessage.success("分享链接已复制到剪贴板");
    console.log("分享链接已复制到剪贴板:", shareUrl);
  } catch (err) {
    console.error("复制失败:", err);
    const textArea = document.createElement("textarea");
    textArea.value = shareUrl;
    document.body.appendChild(textArea);
    textArea.select();
    document.execCommand("copy");
    document.body.removeChild(textArea);
  }
};

const initExcalidraw = () => {
  const savedData = excalidrawStore.getDrawing(currentRoomId);
  const api = (window as any).excalidrawAPI;

  const initialData = {
    elements: savedData?.elements || [],
    appState: {
      ...(savedData?.appState || {
        zenModeEnabled: true,
        viewBackgroundColor: "#a5d8ff",
      }),
      collaborators: [],
    },
    scrollToContent: true,
  };

  const excalidrawConfig: any = {
    initialData,
    langCode: "zh-CN",
    isCollaborating: false,
    UIOptions: {
      canvasActions: {
        loadScene: false,
        saveToActiveFile: false,
        export: false,
      },
    },
    excalidrawAPI: (api) => {
      (window as any).excalidrawAPI = api;
      const elements = api.getSceneElements();
      lastSentElements = JSON.parse(JSON.stringify(elements || []));

      // Only update scene if there are no elements
      if (elements.length === 0 && savedData?.elements) {
        api.updateScene({
          elements: savedData.elements,
          appState: {
            ...(savedData.appState || {}),
            collaborators: [],
          },
        });
      } else {
        api.updateScene({
          appState: {
            collaborators: [],
          },
        });
      }
    },
    onChange: (elements, appState) => {
      // 不再阻塞本地操作，允许实时更新
      sendDrawingData(elements, {
        ...appState,
        collaborators: [],
      });
    },
  };

  reactRoot.render(React.createElement(Excalidraw, excalidrawConfig));
};

watch(
  () => studyRoomStore.currentRoom?.roomId,
  async (newRoomId) => {
    if (newRoomId && newRoomId !== currentRoomId) {
      isReceivingUpdate = true;

      // Save current drawing
      const api = (window as any).excalidrawAPI;
      if (api) {
        const elements = api.getSceneElements();
        excalidrawStore.setCurrentDrawing(currentRoomId, {
          elements,
          appState: {
            ...api.getAppState(),
            collaborators: [],
          },
        });
      }

      if (MQClient.active) {
        await MQClient.deactivate();
      }

      currentRoomId = newRoomId;
      excalidrawStore.setCurrentRoomId(newRoomId);
      await initMQConnection();
      initExcalidraw();

      isReceivingUpdate = false;
      pendingLocalChanges = false;
    }
  }
);

onMounted(() => {
  if (typeof window !== "undefined") {
    isClient.value = true;
    nextTick(() => {
      if (container.value) {
        reactRoot = ReactDOM.createRoot(container.value);
        currentRoomId = getRoomId();
        if (currentRoomId) {
          excalidrawStore.setCurrentRoomId(currentRoomId);
          initMQConnection();
          initExcalidraw();
        }
      }
    });
  }
});

onUnmounted(() => {
  const api = (window as any).excalidrawAPI;
  if (api) {
    const elements = api.getSceneElements();
    excalidrawStore.setCurrentDrawing(currentRoomId, {
      elements,
      appState: {
        ...api.getAppState(),
        collaborators: [],
      },
    });
  }

  if (reactRoot) {
    reactRoot.unmount();
  }
  if (MQClient.active) {
    MQClient.deactivate();
  }
});
</script>

<style scoped>
.excalidraw-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
}

.share-button-container {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1000;
}

.share-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: #ffffff;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.2s ease;
  color: #666;
}

.share-button:hover {
  background: #f5f5f5;
  border-color: #d0d0d0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  color: #333;
}

.share-button:active {
  transform: translateY(1px);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
</style>
